home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Den Norske Hjemmedataklubben / Amiga-Hack 93-1 (1993)(Data-Tronic AS)(NO)(Disk 2 of 2)[b dump].zip / Amiga-Hack 93-1 (1993)(Data-Tronic AS)(NO)(Disk 2 of 2)[b dump].adf / BROWSER / MENU.C < prev    next >
C/C++ Source or Header  |  1992-12-15  |  8KB  |  344 lines

  1. /* easy menus: Copyright 1987 Peter da Silva, all rights reserved.
  2.  *
  3.  *    Permission is granted to use this in any application, so long as
  4.  *    this notice is retained in the source. Permission is granted to
  5.  *    modify the code as you like, so long as this notice (between the
  6.  *    first line beginning "easy menus" and the end of this paragraph,
  7.  *    inclusive) is retained intact.
  8.  *
  9.  * Usage:
  10.  *
  11.  *    #include "menu.h"
  12.  *
  13.  *    struct MenuPtr menudata;
  14.  *    struct MenuPtr *menuptr = &menudata;
  15.  *
  16.  *    init_menus(menuptr);    / * Just zero menu pointer out * /
  17.  *
  18.  *    for(each menu item) {
  19.  *        add_menu(menuptr, menu, item, subitem, flags);
  20.  *    }
  21.  *
  22.  *  Flags:
  23.  *    SUBITEM_NOCHECK    -- subitem does not require a checkmark.
  24.  *    SUBITEM_SELECTOR    -- subitem is a 1 of n selector, use mutual-exclude.
  25.  *    SUBITEM_TOGGLE    -- subitem is a toggled flag.
  26.  *    SUBITEM_SELECTED    -- defaults to checked.
  27.  *
  28.  *
  29.  *    SetMenuStrip(yourwindow, menuptr->MenuBar);
  30.  *
  31.  *    ...
  32.  *
  33.  *    ClearMenuStrip(yourwindow);
  34.  *
  35.  *    trash_menus(menuptr);
  36.  *
  37.  * Notes:
  38.  *
  39.  *    if you don't want any subitems, use zero for the subitem value.
  40.  *
  41.  *    subitem is always initialised as a CHECKIT item with all the other
  42.  *    subitems mutually excluded.
  43.  *
  44.  *    it is intended that the menu be set up with all action items in
  45.  *    the first level of the menu, and all toggles in the second level...
  46.  *    this is a piece of blatant authoritarianism on my part. I've seen
  47.  *    too many menus with no rhyme or reason. Look at AmigaTerm (the term
  48.  *    program that comes with the Amiga modem) some time. Baud rate has
  49.  *    an item all by itself, but word size is hidden off in a menu with
  50.  *    things like bell sound.
  51.  *
  52.  *    the appearance of the menus produced by this is (in my humble
  53.  *    opinion) good. I took some care making text centered in menu boxes,
  54.  *    for example.
  55.  */
  56. #include <exec/memory.h>
  57. #include <intuition/intuition.h>
  58. #include "menu.h"
  59. #include "fonts.h"
  60.  
  61. /* Forward prototypes */
  62. static void nudge(struct MenuItem *item, int delta);
  63. static struct Menu *
  64.     new_menu(struct MenuPtr *menuptr, char *name);
  65. static struct MenuItem *
  66.     new_item(struct MenuPtr *menuptr,
  67.         struct Menu *menu, UBYTE *name);
  68. static struct MenuItem *
  69.     new_subitem(struct MenuPtr *menuptr,
  70.         struct MenuItem *item, UBYTE *name, long flags);
  71.  
  72. /*
  73. struct MenuPtr {
  74.     struct Menu *MenuBar;
  75.     struct Remember *MenuMemory;
  76. };
  77. */
  78.  
  79. char *AllocRemember();
  80.  
  81. static struct Menu *new_menu();
  82. static struct MenuItem *new_item(), *new_subitem();
  83.  
  84. #define TOMENUNUM(i,j,k) (SHIFTMENU(i)|SHIFTITEM(j)|SHIFTSUB(k))
  85. #define TextLen(s) (strlen(s)*FONTWIDTH)
  86.  
  87. void trash_menus(struct MenuPtr *menuptr)
  88. {
  89.     FreeRemember(&menuptr->MenuMemory, 1);
  90.     menuptr->MenuMemory = 0;
  91.     menuptr->MenuBar = 0;
  92. }
  93.  
  94. void init_menus(struct MenuPtr *menuptr)
  95. {
  96.     menuptr->MenuMemory = 0;
  97.     menuptr->MenuBar = 0;
  98. }
  99.  
  100. int add_menu(
  101.     struct MenuPtr *menuptr,
  102.     char *menuname,
  103.     char *itemname,
  104.     char *subitemname,
  105.     long flags)
  106. {
  107.     int i, j, k;
  108.     struct Menu *menu;
  109.     struct MenuItem *item;
  110.     struct MenuItem *subitem;
  111.  
  112.     if(menuptr->MenuBar) {
  113.         for(i = 0, menu = menuptr->MenuBar;
  114.             menu;
  115.             menu = menu->NextMenu, i++
  116.            )
  117.             if(strcmp(menuname, menu->MenuName)==0)
  118.                 break;
  119.         if(!menu)
  120.             menu = new_menu(menuptr, menuname);
  121.         if(!menu)
  122.             return MENUNULL;
  123.     } else {
  124.         i = 0;
  125.         menu = new_menu(menuptr, menuname);
  126.         if(!menu)
  127.             return MENUNULL;
  128.     }
  129.     for(j = 0, item = menu->FirstItem;
  130.         item;
  131.         item = item->NextItem, j++
  132.        ) {
  133.         struct IntuiText *text;
  134.         text = (struct IntuiText *)item->ItemFill;
  135.         if(strcmp(itemname, text->IText) == 0)
  136.             break;
  137.     }
  138.     if(subitemname) {
  139.         if(!item)
  140.             item = new_item(menuptr, menu, (UBYTE *)itemname);
  141.         if(!item)
  142.             return MENUNULL;
  143.         for(k = 0, subitem = item->SubItem;
  144.             subitem;
  145.             subitem = subitem->NextItem, k++
  146.            ) {
  147.             struct IntuiText *text;
  148.             text = (struct IntuiText *)subitem->ItemFill;
  149.             if(strcmp(subitemname, text->IText) == 0)
  150.                 break;
  151.         }
  152.         if(!subitem)
  153.             subitem = new_subitem(menuptr, item, (UBYTE *)subitemname, flags);
  154.         if(!subitem)
  155.             return MENUNULL;
  156.         return TOMENUNUM(i, j, k);
  157.     } else {
  158.         if(!item)
  159.             item = new_item(menuptr, menu, (UBYTE *)itemname);
  160.         if(!item)
  161.             return MENUNULL;
  162.         return TOMENUNUM(i, j, NOSUB);
  163.     }
  164. }
  165.  
  166. static struct Menu *
  167. new_menu(struct MenuPtr *menuptr, char *name)
  168. {
  169.     struct Menu *menu;
  170.  
  171.     menu = (struct Menu *)AllocRemember(
  172.         &menuptr->MenuMemory,
  173.         sizeof(struct Menu),
  174.         MEMF_PUBLIC);
  175.     if(!menu)
  176.         return 0;
  177.     menu->NextMenu = NULL;
  178.     menu->LeftEdge = 0;
  179.     menu->TopEdge = 0;
  180.     menu->Width = TextLen(name)+FONTWIDTH;
  181.     menu->Height = 0;
  182.     menu->Flags = MENUENABLED;
  183.     menu->MenuName = name;
  184.     menu->FirstItem = 0;
  185.     if(menuptr->MenuBar) {
  186.         struct Menu *ptr, *prev;
  187.         for(ptr = menuptr->MenuBar; ptr; ptr=ptr->NextMenu) {
  188.             menu->LeftEdge += ptr->Width;
  189.             prev = ptr;
  190.         }
  191.         prev->NextMenu = menu;
  192.     } else {
  193.         menuptr->MenuBar = menu;
  194.     }
  195.  
  196.     return menu;
  197. }
  198.  
  199. static struct MenuItem *
  200. new_item(struct MenuPtr *menuptr, struct Menu *menu, UBYTE *name)
  201. {
  202.     struct MenuItem *item;
  203.     struct IntuiText *text;
  204.  
  205.     item = (struct MenuItem *)AllocRemember(
  206.         &menuptr->MenuMemory,
  207.         sizeof(struct MenuItem),
  208.         MEMF_PUBLIC);
  209.     if(!item)
  210.         return 0;
  211.     text = (struct IntuiText *)AllocRemember(
  212.         &menuptr->MenuMemory,
  213.         sizeof(struct IntuiText),
  214.         MEMF_PUBLIC);
  215.     if(!text)
  216.         return 0;
  217.  
  218.     text->FrontPen = AUTOFRONTPEN;
  219.     text->BackPen = AUTOBACKPEN;
  220.     text->DrawMode = JAM2;
  221.     text->LeftEdge = 1;
  222.     text->TopEdge = 1;
  223.     text->ITextFont = NULL;
  224.     text->IText = name;
  225.     text->NextText = NULL;
  226.  
  227.     item->NextItem = NULL;
  228.     item->LeftEdge = 0;
  229.     item->TopEdge = 0;
  230.     item->Width = IntuiTextLength(text)+2;
  231.     if(item->Width <= menu->Width)
  232.         item->Width = menu->Width+1;
  233.     item->Height = FONTHEIGHT+1;
  234.     item->Flags = ITEMTEXT|HIGHCOMP|ITEMENABLED;
  235.     item->MutualExclude = 0;
  236.     item->ItemFill = (APTR)text;
  237.     item->SelectFill = NULL;
  238.     item->Command = 0;
  239.     item->SubItem = NULL;
  240.     item->NextSelect = NULL;
  241.  
  242.     if(menu->FirstItem) {
  243.         struct MenuItem *ptr, *prev;
  244.         for(ptr = menu->FirstItem; ptr; ptr=ptr->NextItem) {
  245.             if(item->Width > ptr->Width) {
  246.                 if(ptr->SubItem)
  247.                     nudge(ptr->SubItem, item->Width-ptr->Width);
  248.                 ptr->Width = item->Width;
  249.             } else if(ptr->Width>item->Width)
  250.                 item->Width = ptr->Width;
  251.             prev = ptr;
  252.         }
  253.         item->TopEdge = prev->TopEdge + prev->Height;
  254.         prev->NextItem = item;
  255.     } else {
  256.         menu->FirstItem = item;
  257.     }
  258.  
  259.     return item;
  260. }
  261.  
  262. static void nudge(struct MenuItem *item, int delta)
  263. {
  264.     while(item) {
  265.         item->LeftEdge += delta;
  266.         item = item->NextItem;
  267.     }
  268. }
  269.  
  270. static struct MenuItem *
  271. new_subitem(
  272.     struct MenuPtr *menuptr,
  273.     struct MenuItem *item,
  274.     UBYTE *name,
  275.     long flags)
  276. {
  277.     struct MenuItem *subitem;
  278.     struct IntuiText *text;
  279.  
  280.     subitem = (struct MenuItem *)AllocRemember(
  281.         &menuptr->MenuMemory,
  282.         sizeof(struct MenuItem),
  283.         MEMF_PUBLIC);
  284.     if(!subitem)
  285.         return 0;
  286.     text = (struct IntuiText *)AllocRemember(
  287.         &menuptr->MenuMemory,
  288.         sizeof(struct IntuiText),
  289.         MEMF_PUBLIC);
  290.     if(!text)
  291.         return 0;
  292.  
  293.     text->FrontPen = AUTOFRONTPEN;
  294.     text->BackPen = AUTOBACKPEN;
  295.     text->DrawMode = JAM2;
  296.     text->LeftEdge = 1;
  297.     if(flags != SUBITEM_NOCHECK) text->LeftEdge += CHECKWIDTH;
  298.     text->TopEdge = 1;
  299.     text->ITextFont = NULL;
  300.     text->IText = name;
  301.     text->NextText = NULL;
  302.  
  303.     subitem->NextItem = NULL;
  304.     subitem->LeftEdge = item->Width;
  305.     subitem->TopEdge = 0;
  306.     subitem->Width = IntuiTextLength(text)+2;
  307.     if(flags != SUBITEM_NOCHECK) subitem->Width += CHECKWIDTH;
  308.     subitem->Height = FONTHEIGHT+1;
  309.     subitem->Flags = ITEMTEXT|ITEMENABLED|HIGHCOMP;
  310.     subitem->MutualExclude = 0;
  311.     if(flags != SUBITEM_NOCHECK) {
  312.         subitem->Flags |= CHECKIT;
  313.         if(flags & SUBITEM_TOGGLE) subitem->Flags |= MENUTOGGLE;
  314.         if(flags & SUBITEM_SELECTED) subitem->Flags |= CHECKED;
  315.     }
  316.     subitem->ItemFill = (APTR)text;
  317.     subitem->SelectFill = NULL;
  318.     subitem->Command = 0;
  319.     subitem->SubItem = NULL;
  320.     subitem->NextSelect = NULL;
  321.  
  322.     if(item->SubItem) {
  323.         struct MenuItem *ptr, *prev;
  324.         int i;
  325.         for(i=0, ptr = item->SubItem; ptr; i++, ptr=ptr->NextItem) {
  326.             if(subitem->Width > ptr->Width)
  327.                 ptr->Width = subitem->Width;
  328.             else if(ptr->Width>subitem->Width)
  329.                 subitem->Width = ptr->Width;
  330.             prev = ptr;
  331.         }
  332.         subitem->TopEdge = prev->TopEdge + prev->Height;
  333.         if(flags & SUBITEM_SELECTOR)
  334.             subitem->MutualExclude = ~(1<<i);
  335.         prev->NextItem = subitem;
  336.     } else {
  337.         item->SubItem = subitem;
  338.         if(flags & SUBITEM_SELECTOR)
  339.             subitem->MutualExclude = ~1;
  340.     }
  341.  
  342.     return subitem;
  343. }
  344.